package com.kaochong.xcx.service.impl;

import com.google.common.collect.Lists;

import com.kaochong.xcx.cache.PrizeCache;
import com.kaochong.xcx.dao.PrizeMapper;
import com.kaochong.xcx.dao.PrizeUserMapper;
import com.kaochong.xcx.entity.PrizeUser;
import com.kaochong.xcx.entity.Prizes;
import com.kaochong.xcx.entity.User;
import com.kaochong.xcx.enums.ResultEnum;
import com.kaochong.xcx.exception.KaoChongException;
import com.kaochong.xcx.pojo.vo.LuckyVO;
import com.kaochong.xcx.pojo.vo.PrizeUserVO;
import com.kaochong.xcx.pojo.vo.PrizesVO;
import com.kaochong.xcx.properties.WechatAccountProperties;
import com.kaochong.xcx.service.PrizesService;
import com.kaochong.xcx.service.UserService;
import com.kaochong.xcx.utils.DateUtil;
import com.kaochong.xcx.utils.TemplateUtil;
import com.kaochong.xcx.web.aspect.CurrentUser;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;

import lombok.extern.slf4j.Slf4j;

@Service
@Slf4j
public class PrizesServiceImpl implements PrizesService {
    @Autowired
    private PrizeMapper prizeMapper;

    @Autowired
    private PrizeUserMapper prizeUserMapper;

    @Autowired
    private UserService userService;

    @Autowired
    WechatAccountProperties wechatAccountProperties;

    @Autowired
    TemplateUtil templateUtil;

    @Autowired
    PrizeCache prizeCache;

    /**
     * 获取当前抽奖活动
     *
     * @param userId
     * @return
     */
    @Override
    public PrizesVO getCurrentPrize(Long userId) {
        PrizesVO prizesVO = new PrizesVO();
        List<Prizes> prizesList = prizeCache.getPrizeList("all");
        Prizes prizes = null;
        if (prizesList != null) {
            for (Prizes prizesItem : prizesList) {
                if (prizesItem.getState() == 1) {
                    Date now = new Date();
                    if (prizesItem.getStartTime().compareTo(now) == -1 && prizesItem.getEndTime().compareTo(now) == 1) {
                        prizes = prizesItem;
                        break;
                    } else {
                        Prizes prizes1 = prizeMapper.findUnLinePrize();
                        prizesVO.setUserState(-100);
                        prizesVO.setPrizes(prizes1);
                        return prizesVO;
                    }
                }
            }
        }

        if (prizes == null) {
            prizes = prizeMapper.findCurrentPrizes();
            if (prizes == null) {
                Prizes prizes1 = prizeMapper.findUnLinePrize();
                prizesVO.setUserState(-100);
                prizesVO.setPrizes(prizes1);
                return prizesVO;
            }
        }


        /**
         * 判断当前用户资格状态
         *  0 ：没有抽奖资格,需要去背单词
         *  1：有资格没助力，需要邀请好友
         *  2：有资格并已助力，等待开奖
         */
        PrizeUser prizeUser = prizeUserMapper.userIsExist(userId, prizes.getId());
        prizesVO.setPrizes(prizes);
        if (prizeUser == null || ("").equals(prizeUser)) {
            prizesVO.setUserState(0);
        } else if (prizeUser.getFriend() != null && !("").equals(prizeUser.getFriend())) {
            Calendar c = Calendar.getInstance();
            //当前时间小于开奖时间
            if (c.get(Calendar.HOUR_OF_DAY) < prizes.getOpenClock() || prizeUser.getIsLucky() == 0) {
                prizesVO.setUserState(2);
            } else {
                prizesVO.setUserState(3);
            }
        } else {
            prizesVO.setUserState(1);
        }

        return prizesVO;
    }

    /**
     * 将完成一个stage的用户添加到资格表中，用户不能重复，每个用户一天只能添加一次
     *
     * @param userId
     * @param openId
     */
    @Override
    public void insertFinishStagePrizeUser(Long userId, String openId) {
        Prizes prizes = prizeMapper.findCurrentPrizes();
        if (prizes == null) {
            log.error("抱歉，当前没有活动在进行");
            return;
        }
        Integer prizeId = prizeMapper.findCurrentPrizes().getId();
        //判断用户是否已经存在
        PrizeUser userIsExist = prizeUserMapper.userIsExist(userId, prizeId);
        if (userIsExist != null) {
            log.info("今天已获得抽奖资格");
        } else {
            PrizeUser prizeUser = new PrizeUser();
            prizeUser.setUserid(userId);
            prizeUser.setOpenid(openId);
            prizeUser.setPrizeid(prizeId);
            prizeUser.setIsLucky(0);
            prizeUser.setFriendCount(0);
            prizeUserMapper.insert(prizeUser);

        }
    }

    /**
     * 查询我参与抽奖活动的记录-->分页
     *
     * @param userId
     * @param offset
     * @param rows
     * @return
     */
    @Override
    public List<PrizeUserVO> findPrizeUserVO(Long userId, Integer offset, Integer rows) {
        /*String sql = "select bpu.id,bpu.prizeid,bpu.userid,(case when bpu.phone is NULL then  '' else bpu.phone end),bpu.is_lucky,bpu.friend,DATE_FORMAT(DATE_ADD(bpu.create_time, interval 1 day),'%Y-%m-%d') create_time," +
                "bp.prize,bp.prize_img prizeImg,bp.prize_count prizeCount from bdc_prize_user bpu left join bdc_prize bp on bp.id = bpu.prizeid where bpu.friend is not NULL and bpu.friend != '' and bpu.userid = ?1  " +
                " order by create_time desc limit ?2 ,?3";
        Query query = entityManager.createNativeQuery(sql);
        query.setParameter(1, userId);
        query.setParameter(2, offset);
        query.setParameter(3, rows);
        List<Object[]> resultList = query.getResultList();
        List<PrizeUserVO> PrizeUserList = Lists.newArrayList();
        for (Object[] objects : resultList) {
            PrizeUserVO prizeUserVO = new PrizeUserVO();
            prizeUserVO.setId(Integer.parseInt(objects[0].toString()));
            prizeUserVO.setPrizeid(Integer.parseInt(objects[1].toString()));
            prizeUserVO.setUserid(Long.parseLong(objects[2].toString()));
            prizeUserVO.setPhone(objects[3].toString());
            prizeUserVO.setIsLucky(Integer.parseInt(objects[4].toString()));
            prizeUserVO.setFriend(objects[5].toString());
            prizeUserVO.setCreateTime(objects[6].toString());
            prizeUserVO.setPrize(objects[7].toString());
            prizeUserVO.setPrize_img(objects[8].toString());
            prizeUserVO.setPrizeCount(Integer.parseInt(objects[9].toString()));
            PrizeUserList.add(prizeUserVO);
        }
        return PrizeUserList;*/
        List<PrizeUserVO> prizeUserList = prizeUserMapper.selectByUserId(userId, offset, rows);
        return prizeUserList;
    }

    /**
     * 查询获奖幸运儿
     * 因为前端用了错误的字段来展示开奖时间
     * 所以这个方法在接收到的日期参数PrizeDate 需要减去一天
     *
     * @param PrizeDate
     * @return
     */
    @Override
    public Map<String, Object> getLuckyUser(String PrizeDate) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date prizeDate = null;
        String hashDate = null;
        //日期处理
        try {
            Date tmpDate = simpleDateFormat.parse(PrizeDate);
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(tmpDate);
            calendar.add(calendar.DATE, -1);
            hashDate = simpleDateFormat.format(calendar.getTime());
            prizeDate = simpleDateFormat.parse(hashDate);
        } catch (Exception e) {
            e.printStackTrace();
        }
        //缓存中如果有则从缓存中取
        Map mapCache = prizeCache.PhGet(hashDate);
        if (mapCache != null) {
            return mapCache;
        }
        String sql = "select bu.open_id,bu.nickname,bu.portrait,bpu.phone,bpu.prizeid from bdc_user bu  inner join  bdc_prize_user bpu on bpu.userid = bu.id where  DATE_FORMAT(bpu.create_time,'%Y-%m-%d') = DATE_FORMAT(STR_TO_DATE(?1,'%Y-%m-%d'),'%Y-%m-%d') and bpu.is_lucky = 2";
        Query query = entityManager.createNativeQuery(sql);
        query.setParameter(1, prizeDate);
        List<Object[]> resultList = query.getResultList();
        List<LuckyVO> luckyVOList = Lists.newArrayList();
        Prizes prizes = null;
        if (resultList.size() > 0) {
            Integer pid = 0;
            for (Object[] objects : resultList) {
                LuckyVO luckyVO = new LuckyVO();
                luckyVO.setOpenId(objects[0].toString());
                luckyVO.setNickname(objects[1] == null ? "" : objects[1].toString());
                luckyVO.setPortrait(objects[2] == null ? "" : objects[2].toString());
                luckyVO.setPhone(objects[3] == null ? "" : objects[3].toString());
                pid = Integer.parseInt(objects[4].toString());
                luckyVOList.add(luckyVO);
            }
            prizes = prizesRepository.findOne(pid);
        }
        Map<String, Object> map = new HashMap<>();
        map.put("userList", luckyVOList);
        map.put("prize", prizes);
        if (luckyVOList.size() != 0 && prizes != null) {
            prizeCache.PhPut(hashDate, map);
        }
        return map;
    }

    /**
     * 获奖幸运儿添加手机号
     *
     * @param userId
     * @param phone
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void savePhone(Long userId, String phone) {
        prizeUserMapper.updatePhone(userId, phone);
    }

    /**
     * 好友助力
     *
     * @param currentUser
     * @param openId
     * @param prizeid
     * @param helpDate
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void friendHelp(CurrentUser currentUser, String openId, Integer prizeid, String helpDate) {
        /**
         * 1.校验需要解锁日期是否合法 yyyy-MM-dd
         *   【规则】只能助力当天活动，校验传入参数年月日是否与当时相同
         *   【结果】如果日期错误直接返回
         *   【目的】防止点击以前的分享
         */
        int dateFlag = 0;
        try {
            String dateStr = String.format("%tF%n", new Date()); //获取当前年月日
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
            dateFlag = simpleDateFormat.parse(helpDate).compareTo(simpleDateFormat.parse(dateStr));
        } catch (Exception e) {
            throw new KaoChongException(ResultEnum.PARAM_ERROR);
        }
        if (dateFlag < 0) {
            log.info("【【抽奖-好友助力】抱歉，只能助力当日的活动");
            return;
        } else if (dateFlag > 0) {
            log.info("【抽奖-好友助力】抱歉，助力的活动还未开始");
            return;
        }

        /**
         * 【目的】兼容前端参数helpDate“不传时分秒“问题
         * 【规则】如果得不到时分秒，并且抽奖活动开始时间为今天，那么可能导致查不到活动
         *        要让活动到点自动上线，必须要精确到时分秒，给时间追加23:59:59，
         *        默认只有活动上线后，才有分享助力事件
         */
        if (helpDate.contains("-") && helpDate.length() == 10) {
            helpDate = helpDate + " 23:59:59";
        }
        Date compareDate = null;
        try {
            SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            compareDate = simpleDateFormat1.parse(helpDate);
        } catch (Exception e) {
            throw new KaoChongException(ResultEnum.PARAM_ERROR);
        }
        /**
         * 2.校验是否为同一人
         *   【规则】不能自己给自己助力
         */
        if (openId.equals(currentUser.getOpenId())) {
            log.info("【抽奖-好友助力】抱歉，自己不能助力自己的抽奖");
            return;
        }


        /**
         * 3.校验用户是否已经被助力
         *   【规则】助力只需一次
         *   【方式】先从redis中校验一次，在从数据库校验一次，防止因为redis出现问题而导致错误插入
         */
        boolean myexists = prizeCache.hExists("mine", openId);
        if (myexists) {
            log.info("【抽奖-好友助力】已经被助力，无法再次助力");
            prizeUserMapper.saveFriendCount(openId, helpDate);
            return;
        } else {
            //数据库校验
            PrizeUser prizeUser = prizeUserMapper.findByPrizeidAndCreateTimeaAndOpenid(openId, prizeid, helpDate);
            if (prizeUser == null) {
                log.info("【抽奖-好友助力】被助力的用户没有抽奖资格");
                return;
            }
            if (prizeUser.getFriend() != null && !("").equals(prizeUser.getFriend())) {
                log.info("【抽奖-好友助力】已经被助力，无法再次助力");
                prizeUserMapper.saveFriendCount(openId, helpDate);
                return;
            }
        }

        /**
         * 4.校验来助力的好友今天是否已经出过力
         *   【规则】一个人一天只能帮助一个好友
         *   【方式】先从redis中校验一次，在从数据库校验一次，防止因为redis出现问题而导致错误插入
         */
        boolean friendexists = prizeCache.hExists("friend", currentUser.getOpenId());
        if (friendexists) {
            log.info("【抽奖-好友助力】辛苦，您已经帮助过其他好友了");
            return;
        } else {
            PrizeUser friendInfo = prizeUserMapper.findByFriend(currentUser.getOpenId());
            if (friendInfo != null) {
                log.info("【抽奖-好友助力】辛苦，您已经帮助过其他好友了");
                return;
            }
        }
        /**
         * 5.校验活动的有效性
         *  【规则】如果当前没有活动进行，如紧急下线，则活动无效
         */
        Prizes prizes = null;
        //从缓存中取
        List<Prizes> prizesList = prizeCache.getPrizeList("all");
        if (prizesList != null) {
            for (Prizes prizesItem : prizesList) {
                if (prizesItem.getId() == prizeid && prizesItem.getState() == 1 && prizesItem.getStartTime().compareTo(compareDate) == -1 && prizesItem.getEndTime().compareTo(compareDate) == 1) {
                    prizes = prizesItem;
                    break;
                }
            }
        } else {
            prizes = prizeMapper.findByIdAndStartTimeBetweenAndEndTime(prizeid, helpDate);
        }
        if (prizes == null) {
            log.info("【抽奖-好友助力】抱歉，查询活动已下线");
            return;
        }

        /**
         * 6.所有校验通过，开始添加助力相关信息，插入数据库与redis中
         */
        prizeCache.hPut("mine", openId, currentUser.getOpenId());
        prizeCache.hPut("friend", currentUser.getOpenId(), openId);
        prizeUserMapper.saveFriend(currentUser.getOpenId(), openId, helpDate);
        /**
         * 7.发送模板消息
         * 【规则】新增规则，如果发送不成功，循环尝试，结束条件：a.发送成功 b.formId全部消费完
         */
        int openClock = prizes.getOpenClock();
        String prizeOpenTime = String.format("次日中午%s点", openClock > 12 ? openClock - 12 : openClock);
        String TemplateId = wechatAccountProperties.getJoinTemplateId();
        String TempPage = wechatAccountProperties.getTemplatePage() + String.format("?prizeId=%s", prizes.getId()) + String.format("&isopen=%s", "0") + String.format("&opendate=%s", helpDate);
        String[] keywordInArray = {prizes.getTitle(), prizes.getPrize(), prizeOpenTime};
        Integer sendFlag = -1;
        while (sendFlag != 0 ) {
            // 41028 formId不正确，或者过期
            // 41029 formId已被使用
            if(sendFlag == 41028 || sendFlag == 41029) {
                sendFlag = templateUtil.sendTemplateMessage(openId, TemplateId, TempPage, keywordInArray, 2);
            } else {
                return;
            }
        }
    }

    /**
     * 进行抽奖抽取幸运儿
     *
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public HashSet<User> getAllLuckyUser(String prizeDate) {
        /**
         * 1.检查是否已经抽奖
         */
        if (prizeDate == null) {
            prizeDate = DateUtil.getYesterday("yyyy-MM-dd");//抽取时间为昨天
        }
        PrizeUser prizeUser = prizeUserMapper.findAllLuckyUser(prizeDate);
        if (prizeUser == null) {
            throw new KaoChongException(1011, "【抽奖活动】没有找到具有本次抽奖资格的用户");
        }
        if (prizeUser.getIsLucky() != 0) {
            throw new KaoChongException(1010, "【抽奖活动】今天已经抽过奖了，不要再来一次了");
        }
        /**
         * 2.开始抽奖逻辑
         */
        List<User> userList = userService.findAllLuckyUser(prizeDate); //获取所有有资格进行抽奖的用户
        if (userList.size() == 0) {
            throw new KaoChongException(1011, "【抽奖活动】没有找到具有本次抽奖资格的用户");
        }

        Prizes prizes = prizeMapper.selectByPrimaryKey(prizeUser.getPrizeid()); //获取本次抽奖奖品数量
        if (prizes.getPrizeCount() < 1) {
            throw new KaoChongException(1012, "【抽奖活动】错误的奖品数量");
        }
        HashSet<User> prizeUserSet = new HashSet<>(); //中奖用户Response容器
        List<Long> prizeUserList = Lists.newArrayList();//中奖用户Database容器
        int prizeDoCount = Math.min(userList.size(), prizes.getPrizeCount());//进行抽奖次数，防止出现资格用户数量小于奖品数量
        Random random = new Random();
        while (prizeUserSet.size() < prizeDoCount) {
            int luckyUserIndex = random.nextInt(userList.size());//抽取中奖用户
            prizeUserSet.add(userList.get(luckyUserIndex));//添加到Response容器
        }
        /**
         * 修改中奖用户状态
         */
        for (User user : prizeUserSet) {
            prizeUserList.add(user.getId());//添加到Database容器
        }
        String str = "(";
        for (int i = 0; i < prizeUserList.size(); i++) {
            str = str + prizeUserList.get(i);
            if (i != prizeUserList.size() - 1) {
                str = str + ",";
            } else {
                str = str + ")";
            }
        }
        String prize_sql = " update bdc_prize_user set is_lucky = 2 where is_lucky = 0 and DATE_FORMAT(create_time,'%Y-%m-%d') = DATE_FORMAT(STR_TO_DATE(?1,'%Y-%m-%d '),'%Y-%m-%d') and userid in ";
        String not_prize_sql = " update bdc_prize_user set is_lucky = 1 where is_lucky = 0 and DATE_FORMAT(create_time,'%Y-%m-%d') = DATE_FORMAT(STR_TO_DATE(?1,'%Y-%m-%d '),'%Y-%m-%d') and userid not in ";
        prize_sql = prize_sql + str;
        not_prize_sql = not_prize_sql + str;
        /**
         * 修改中奖用户state
         */
        Query prizeQuery = entityManager.createNativeQuery(prize_sql);
        prizeQuery.setParameter(1, prizeDate);
        int prize_sql_update = prizeQuery.executeUpdate();
        /**
         * 修改未中奖用户state
         */
        Query notPrizeQuery = entityManager.createNativeQuery(not_prize_sql);
        notPrizeQuery.setParameter(1, prizeDate);
        int not_prize_sql_update = notPrizeQuery.executeUpdate();
        log.info(String.format("【抽奖活动】修改%s个中奖用户状态，已生效", prize_sql_update));
        log.info(String.format("【抽奖活动】修改%s个未中奖用户状态，已生效", not_prize_sql_update));
        /**
         * 发送模板消息
         */
//        for (User userItem : userList) {
//            String formId = formIdCache.getValidFormId(userItem.getOpenId());
//            if (StringUtils.isNotBlank(formId)) {
//                String TemplateId = wechatAccountProperties.getPrizeTemplateId();
//                String TempPage = wechatAccountProperties.getTemplatePage()+String.format("?prizeId=%s",prizes.getId())+String.format("&isopen=%s","1")+String.format("&opendate=%s",DateUtil.getCurrent());
//                String[] keywordInArray = {CommonConstant.PRIZE_RESULT, CommonConstant.PRIZE_TIPS};
//                templateUtil.sendTemplateMessage(userItem.getOpenId(), formId, TemplateId, TempPage, keywordInArray, -2);
//            }
//        }

        return prizeUserSet;
    }

    /**
     * 当前是否有抽奖活动在进行
     * 控制前端抽奖按钮是否显示
     */
    @Override
    public Integer getPrizeState() {
        List<Prizes> prizeList = prizeCache.getPrizeList("all");
        if (prizeList == null) {
            prizeList = prizeMapper.findPrizeList();
            prizeCache.setPrizeList("all", prizeList);
        }
        Integer prizeState = -1001;
        if (prizeList.size() > 0) {
            for (Prizes prizeItem : prizeList) {
                if (prizeItem.getState() == 1) {
                    if (prizeItem.getEndTime().getTime() < System.currentTimeMillis()) {
                        if (System.currentTimeMillis() - prizeItem.getEndTime().getTime() < 86400000) {
                            prizeState = -100;//活动过期，但保留
                        } else {
                            prizeState = 0;
                        }
                    } else {
                        prizeState = prizeItem.getId();
                    }
                    break;
                }
            }
            if (prizeState == -1001) {
                Prizes prizes = prizeList.get(0);
                if (prizes.getUnLineTime() != null && System.currentTimeMillis() - prizes.getUnLineTime().getTime() < 86400000) {
                    prizeState = -100;//活动下线，但保留
                } else {
                    prizeState = 0;
                }
            }
        } else {
            prizeState = 0;
        }
        return prizeState;
    }

}
